home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-28  |  11.5 KB  |  585 lines

  1. /*
  2.  *  S E N D . C 
  3.  *
  4.  *  EE/CIS Computer Lab
  5.  *  Department of Computer and Information Sciences
  6.  *  Department of Electrical Engineering
  7.  *  University of Delaware
  8.  *
  9.  *  REVISION HISTORY:
  10.  *
  11.  *  $Revision: 1.4 $
  12.  *
  13.  *  $Log:    send.c,v $
  14.  * Revision 1.4  86/01/14  16:29:24  galvin
  15.  * Change send() to check for From line instead of believing it is there.
  16.  * 
  17.  * Change sendmail() to extract()/detract() the To field.
  18.  * 
  19.  * mail1() needed some tuning and cleaning.  Basically change it to
  20.  * interface to the MMDF ml_* routines.  One other major change was to
  21.  * take out the call to verify() and depend on MMDF to do it.  We have
  22.  * to do this anyway since we are allowing address forms that choke Mail.
  23.  * 
  24.  * Change savemail() to include MMDF delimiters.
  25.  * 
  26.  * Revision 1.3  86/01/02  14:29:57  galvin
  27.  * Add another parameter to send to indicate whether or not this message
  28.  * should be delimited by MMDF message delimiters.
  29.  * 
  30.  * Revision 1.2  85/12/18  03:00:41  galvin
  31.  * Added comment header for revision history.
  32.  * 
  33.  *
  34.  */
  35.  
  36. /*
  37.  * Copyright (c) 1980 Regents of the University of California.
  38.  * All rights reserved.  The Berkeley software License Agreement
  39.  * specifies the terms and conditions for redistribution.
  40.  */
  41.  
  42. #ifndef lint
  43. static char *sccsid = "@(#)send.c    5.2 (Berkeley) 6/21/85";
  44. #endif not lint
  45.  
  46. #include "./rcv.h"
  47. #include <ctype.h>
  48. #include <sys/stat.h>
  49.  
  50. #include "./mmdf.h"
  51.  
  52. /*
  53.  * Mail -- a mail program
  54.  *
  55.  * Mail to others.
  56.  */
  57.  
  58. /*
  59.  * Send message described by the passed pointer to the
  60.  * passed output buffer.  Return -1 on error, but normally
  61.  * the number of lines written.  Adjust the status: field
  62.  * if need be.  If doign is set, suppress ignored header fields.
  63.  * If delim is set, output MMDF delimiters around message.
  64.  */
  65. send(mailp, obuf, doign, delim)
  66.     struct message *mailp;
  67.     FILE *obuf;
  68.     int delim;
  69. {
  70.     register struct message *mp;
  71.     long c;
  72.     FILE *ibuf;
  73.     char line[LINESIZE], field[BUFSIZ];
  74.     int lc, ishead, infld, fline, dostat;
  75.     char *cp, *cp2;
  76.  
  77.     mp = mailp;
  78.     ibuf = setinput(mp);
  79.     c = mp->m_size;
  80.     ishead = 1;
  81.     dostat = 1;
  82.     infld = 0;
  83.     fline = 1;
  84.     lc = 0;
  85.     if (delim)
  86.         fputs(delim1, obuf);
  87.     while (c > 0L) {
  88.         fgets(line, LINESIZE, ibuf);
  89.         c -= (long) strlen(line);
  90.         lc++;
  91.         if (ishead) {
  92.             /* 
  93.              * If first line is the "From line", then just print.
  94.              * Since we are dealing with MMDF, it probably isn't.
  95.              */
  96.             if (fline) {
  97.                 fline = 0;
  98.                 if (!strncmp(line, "From ", 5))
  99.                 goto writeit;
  100.             }
  101.             /*
  102.              * If line is blank, we've reached end of
  103.              * headers, so force out status: field
  104.              * and note that we are no longer in header
  105.              * fields
  106.              */
  107.             if (line[0] == '\n') {
  108.                 if (dostat) {
  109.                     statusput(mailp, obuf, doign);
  110.                     dostat = 0;
  111.                 }
  112.                 ishead = 0;
  113.                 goto writeit;
  114.             }
  115.             /*
  116.              * If this line is a continuation (via space or tab)
  117.              * of a previous header field, just echo it
  118.              * (unless the field should be ignored).
  119.              */
  120.             if (infld && (isspace(line[0]) || line[0] == '\t')) {
  121.                 if (doign && isign(field)) continue;
  122.                 goto writeit;
  123.             }
  124.             infld = 0;
  125.             /*
  126.              * If we are no longer looking at real
  127.              * header lines, force out status:
  128.              * This happens in uucp style mail where
  129.              * there are no headers at all.
  130.              */
  131.             if (!headerp(line)) {
  132.                 if (dostat) {
  133.                     statusput(mailp, obuf, doign);
  134.                     dostat = 0;
  135.                 }
  136.                 putc('\n', obuf);
  137.                 ishead = 0;
  138.                 goto writeit;
  139.             }
  140.             infld++;
  141.             /*
  142.              * Pick up the header field.
  143.              * If it is an ignored field and
  144.              * we care about such things, skip it.
  145.              */
  146.             cp = line;
  147.             cp2 = field;
  148.             while (*cp && *cp != ':' && !isspace(*cp))
  149.                 *cp2++ = *cp++;
  150.             *cp2 = 0;
  151.             if (doign && isign(field))
  152.                 continue;
  153.             /*
  154.              * If the field is "status," go compute and print the
  155.              * real Status: field
  156.              */
  157.             if (icequal(field, "status")) {
  158.                 if (dostat) {
  159.                     statusput(mailp, obuf, doign);
  160.                     dostat = 0;
  161.                 }
  162.                 continue;
  163.             }
  164.         }
  165. writeit:
  166.         fputs(line, obuf);
  167.         if (ferror(obuf))
  168.             return(-1);
  169.     }
  170.     if (delim)
  171.         fputs(delim2, obuf);
  172.     if (ferror(obuf))
  173.         return(-1);
  174.     if (ishead && (mailp->m_flag & MSTATUS))
  175.         printf("failed to fix up status field\n");
  176.     return(lc);
  177. }
  178.  
  179. /*
  180.  * Test if the passed line is a header line, RFC 733 style.
  181.  */
  182. headerp(line)
  183.     register char *line;
  184. {
  185.     register char *cp = line;
  186.  
  187.     while (*cp && !isspace(*cp) && *cp != ':')
  188.         cp++;
  189.     while (*cp && isspace(*cp))
  190.         cp++;
  191.     return(*cp == ':');
  192. }
  193.  
  194. /*
  195.  * Output a reasonable looking status field.
  196.  * But if "status" is ignored and doign, forget it.
  197.  */
  198. statusput(mp, obuf, doign)
  199.     register struct message *mp;
  200.     register FILE *obuf;
  201. {
  202.     char statout[3];
  203.  
  204.     if (doign && isign("status"))
  205.         return;
  206.     if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
  207.         return;
  208.     if (mp->m_flag & MREAD)
  209.         strcpy(statout, "R");
  210.     else
  211.         strcpy(statout, "");
  212.     if ((mp->m_flag & MNEW) == 0)
  213.         strcat(statout, "O");
  214.     fprintf(obuf, "Status: %s\n", statout);
  215. }
  216.  
  217.  
  218. /*
  219.  * Interface between the argument list and the mail1 routine
  220.  * which does all the dirty work.
  221.  */
  222.  
  223. mail(people)
  224.     char **people;
  225. {
  226.     register char *cp2;
  227.     register int s;
  228.     char *buf, **ap;
  229.     struct header head;
  230.  
  231.     for (s = 0, ap = people; *ap != (char *) -1; ap++)
  232.         s += strlen(*ap) + 1;
  233.     buf = salloc(s+1);
  234.     cp2 = buf;
  235.     for (ap = people; *ap != (char *) -1; ap++) {
  236.         cp2 = copy(*ap, cp2);
  237.         *cp2++ = ' ';
  238.     }
  239.     if (cp2 != buf)
  240.         cp2--;
  241.     *cp2 = '\0';
  242.     head.h_to = buf;
  243.     head.h_subject = NOSTR;
  244.     head.h_cc = NOSTR;
  245.     head.h_bcc = NOSTR;
  246.     head.h_seq = 0;
  247.     mail1(&head);
  248. }
  249.  
  250.  
  251. /*
  252.  * Send mail to a bunch of user names.  The interface is through
  253.  * the mail routine below.
  254.  */
  255.  
  256. sendmail(str)
  257.     char *str;
  258. {
  259.     struct header head;
  260.  
  261.     if (blankline(str))
  262.         head.h_to = NOSTR;
  263.     else
  264.         head.h_to = detract(elide(extract(str, GTO)), GTO);
  265.     head.h_subject = NOSTR;
  266.     head.h_cc = NOSTR;
  267.     head.h_bcc = NOSTR;
  268.     head.h_seq = 0;
  269.     mail1(&head);
  270.     return(0);
  271. }
  272.  
  273. /*
  274.  * Mail a message on standard input to the people indicated
  275.  * in the passed header.  (Internal interface).
  276.  */
  277.  
  278. mail1(hp)
  279.     struct header *hp;
  280. {
  281.     register char *cp;
  282.     int gotcha;
  283.     struct name *to, *np;
  284.     struct stat sbuf;
  285.     FILE *mtf, *postage;
  286.     int remote = rflag != NOSTR || rmail;
  287.  
  288.     /*
  289.      * Collect user's mail from standard input.
  290.      * Get the result as mtf.
  291.      */
  292.  
  293.     if ((mtf = collect(hp)) == NULL)
  294.         return;
  295.     hp->h_seq = 1;
  296.     if (hp->h_subject == NOSTR)
  297.         hp->h_subject = sflag;
  298.     if (intty && value("askcc") != NOSTR)
  299.         grabh(hp, GCC);
  300.     else if (intty) {
  301.         printf("EOT\n");
  302.         fflush(stdout);
  303.     }
  304.  
  305.     /*
  306.      * Now, get the user names from the combined to and cc lists
  307.      */
  308.  
  309.     senderr = 0;
  310.     to = usermap(cat(extract(hp->h_bcc, GBCC),
  311.         cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC))));
  312.     if (to == NIL) {
  313.         printf("No recipients specified\n");
  314.         goto topdog;
  315.     }
  316.  
  317.     /*
  318.      * Look through the recipient list for names with /'s
  319.      * in them which we write to as files directly.
  320.      */
  321.  
  322.     to = outof(to, mtf, hp);
  323.     if (senderr && !remote) {
  324. topdog:
  325.         rewind(mtf);
  326.         if ((mtf = infix(hp, mtf)) == NULL) {
  327.             fprintf(stderr, ". . . message lost, sorry.\n");
  328.             return;
  329.         }
  330.         if (fsize(mtf) != 0) {
  331.             remove(deadlettername);
  332.             exwrite(deadlettername, mtf, 1);
  333.         }
  334.         goto out;
  335.     }
  336.     for (gotcha = 0, np = to; np != NIL; np = np->n_flink)
  337.         if ((np->n_type & GDEL) == 0) {
  338.             gotcha++;
  339.             break;
  340.         }
  341.     if (!gotcha)
  342.         goto out;
  343.     to = elide(to);
  344.     if (count(to) > 1)
  345.         hp->h_seq++;
  346.     hp->h_to = detract(to, GTO|GCOMMA);
  347.     hp->h_cc = detract(to, GCC|GCOMMA);
  348.     hp->h_bcc = detract(to, GBCC|GCOMMA);
  349.     if (hp->h_seq > 0 && !remote) {
  350.         if (fsize(mtf) == 0)
  351.             if (hp->h_subject == NOSTR)
  352.             printf("No message, no subject; hope that's ok\n");
  353.             else
  354.             printf("No message; hope that's ok\n");
  355.         }
  356.     if (debug) {
  357.         printf("Recipients of message:\n");
  358.         if (hp->h_to != NOSTR)
  359.             printf(" \"%s\"", hp->h_to);
  360.         if (hp->h_cc != NOSTR)
  361.             printf(" \"%s\"", hp->h_cc);
  362.         if (hp->h_bcc != NOSTR)
  363.             printf(" \"%s\"", hp->h_bcc);
  364.         printf("\n");
  365.         fflush(stdout);
  366.         return;
  367.     }
  368.     rewind(mtf);
  369.     if (ml_init(YES, NO, NOSTR, hp->h_subject) != OK)
  370.         goto topdog;
  371.     if (!isnull(hp->h_to) && ml_adr(hp->h_to) != OK)
  372.         goto topdog;
  373.     if (!isnull(hp->h_cc) && ml_cc() != OK || ml_adr(hp->h_cc) != OK)
  374.         goto topdog;
  375.     if (!isnull(hp->h_bcc) && ml_adr(hp->h_bcc) != OK)
  376.         goto topdog;
  377.     if (ml_aend() != OK)
  378.         goto topdog;
  379.     if (ml_tinit() != OK)
  380.         goto topdog;
  381.     if (ml_file(mtf) != OK)
  382.         goto topdog;
  383.     if (ml_end(OK) != OK)
  384.         goto topdog;
  385.     rewind(mtf);
  386.     if ((mtf = infix(hp, mtf)) == NULL) {
  387.         fprintf(stderr, ". . . message lost, sorry.\n");
  388.         return;
  389.     }
  390.  
  391.     rewind(mtf);
  392.     if ((cp = value("record")) != NOSTR)
  393.         savemail(expand(cp), mtf);
  394.  
  395.         if (!stat(POSTAGE, &sbuf))
  396.             if ((postage = fopen(POSTAGE, "a")) != NULL) {
  397.                 fprintf(postage, "%s %d %d\n", myname,
  398.                     count(to), fsize(mtf));
  399.                 fclose(postage);
  400.             }
  401. out:
  402.     fclose(mtf);
  403.     return;
  404. }
  405.  
  406. #ifdef NOT_USED
  407. /*
  408.  * Fix the header by glopping all of the expanded names from
  409.  * the distribution list into the appropriate fields.
  410.  * If there are any ARPA net recipients in the message,
  411.  * we must insert commas, alas.
  412.  */
  413.  
  414. fixhead(hp, tolist)
  415.     struct header *hp;
  416.     struct name *tolist;
  417. {
  418.     register int f;
  419.     register struct name *np;
  420.  
  421.     for (f = 0, np = tolist; np != NIL; np = np->n_flink)
  422.         if (any('@', np->n_name)) {
  423.             f |= GCOMMA;
  424.             break;
  425.         }
  426.  
  427.     if (debug && f & GCOMMA)
  428.         fprintf(stderr, "Should be inserting commas in recip lists\n");
  429.     hp->h_to = detract(tolist, GTO|f);
  430.     hp->h_cc = detract(tolist, GCC|f);
  431. }
  432. #endif NOT_USED
  433.  
  434. /*
  435.  * Prepend a header in front of the collected stuff
  436.  * and return the new file.
  437.  */
  438.  
  439. FILE *
  440. infix(hp, fi)
  441.     struct header *hp;
  442.     FILE *fi;
  443. {
  444.     extern char tempMail[];
  445.     register FILE *nfo, *nfi;
  446.     register int c;
  447.  
  448.     rewind(fi);
  449.     if ((nfo = fopen(tempMail, "w")) == NULL) {
  450.         perror(tempMail);
  451.         return(fi);
  452.     }
  453.     if ((nfi = fopen(tempMail, "r")) == NULL) {
  454.         perror(tempMail);
  455.         fclose(nfo);
  456.         return(fi);
  457.     }
  458.     remove(tempMail);
  459.     puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL);
  460.     c = getc(fi);
  461.     while (c != EOF) {
  462.         putc(c, nfo);
  463.         c = getc(fi);
  464.     }
  465.     if (ferror(fi)) {
  466.         perror("read");
  467.         return(fi);
  468.     }
  469.     fflush(nfo);
  470.     if (ferror(nfo)) {
  471.         perror(tempMail);
  472.         fclose(nfo);
  473.         fclose(nfi);
  474.         return(fi);
  475.     }
  476.     fclose(nfo);
  477.     fclose(fi);
  478.     rewind(nfi);
  479.     return(nfi);
  480. }
  481.  
  482. /*
  483.  * Dump the to, subject, cc header on the
  484.  * passed file buffer.
  485.  */
  486.  
  487. puthead(hp, fo, w)
  488.     struct header *hp;
  489.     FILE *fo;
  490. {
  491.     register int gotcha;
  492.  
  493.     gotcha = 0;
  494.     if (hp->h_to != NOSTR && w & GTO)
  495.         fmt("To: ", hp->h_to, fo), gotcha++;
  496.     if (hp->h_subject != NOSTR && w & GSUBJECT)
  497.         fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
  498.     if (hp->h_cc != NOSTR && w & GCC)
  499.         fmt("Cc: ", hp->h_cc, fo), gotcha++;
  500.     if (hp->h_bcc != NOSTR && w & GBCC)
  501.         fmt("Bcc: ", hp->h_bcc, fo), gotcha++;
  502.     if (gotcha && w & GNL)
  503.         putc('\n', fo);
  504. }
  505.  
  506. /*
  507.  * Format the given text to not exceed 72 characters.
  508.  */
  509.  
  510. fmt(str, txt, fo)
  511.     register char *str, *txt;
  512.     register FILE *fo;
  513. {
  514.     register int col;
  515.     register char *bg, *bl, *pt, ch;
  516.  
  517.     col = strlen(str);
  518.     if (col)
  519.         fprintf(fo, "%s", str);
  520.     pt = bg = txt;
  521.     bl = 0;
  522.     while (*bg) {
  523.         pt++;
  524.         if (++col >72) {
  525.             if (!bl) {
  526.                 bl = bg;
  527.                 while (*bl && !isspace(*bl))
  528.                     bl++;
  529.             }
  530.             if (!*bl)
  531.                 goto finish;
  532.             ch = *bl;
  533.             *bl = '\0';
  534.             fprintf(fo, "%s\n    ", bg);
  535.             col = 4;
  536.             *bl = ch;
  537.             pt = bg = ++bl;
  538.             bl = 0;
  539.         }
  540.         if (!*pt) {
  541. finish:
  542.             fprintf(fo, "%s\n", bg);
  543.             return;
  544.         }
  545.         if (isspace(*pt))
  546.             bl = pt;
  547.     }
  548. }
  549.  
  550. /*
  551.  * Save the outgoing mail on the passed file.
  552.  */
  553.  
  554. savemail(name, fi)
  555.     char name[];
  556.     FILE *fi;
  557. {
  558.     register FILE *fo;
  559.     register int c;
  560.     time_t time();
  561.     time_t now;
  562.     char *ctime();
  563.     char *n;
  564.  
  565.     if ((fo = fopen(name, "a")) == NULL) {
  566.         perror(name);
  567.         return;
  568.     }
  569.     time(&now);
  570.     n = rflag;
  571.     if (n == NOSTR)
  572.         n = myname;
  573.     fputs(delim1, fo);
  574.     fprintf(fo, "From %s %s", n, ctime(&now));
  575.     rewind(fi);
  576.     for (c = getc(fi); c != EOF; c = getc(fi))
  577.         putc(c, fo);
  578.     fprintf(fo, "\n");
  579.     fputs(delim2, fo);
  580.     fflush(fo);
  581.     if (ferror(fo))
  582.         perror(name);
  583.     fclose(fo);
  584. }
  585.